#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <math.h>

#include <drm/drm.h>

static char *drm_file = "/dev/dri/card0";
static int drm_fd = -1;
static struct drm_mode_card_res res;
static struct drm_mode_get_connector *conn = NULL;
static int connectors_valid = 0;
static int mode_index = 0;

#define CONNECTOR_MAX   3
typedef struct {
    struct drm_mode_get_connector *conn;
    struct drm_mode_get_encoder enc;
    struct drm_mode_crtc crtc;
    struct drm_mode_create_dumb create_dumb;
    struct drm_mode_destroy_dumb destroy_dumb;
    struct drm_mode_map_dumb map_dumb;
    struct drm_mode_fb_cmd cmd_dumb;
    unsigned char *fb_base;
} connector_res_t;
connector_res_t *connector_res;

static int clear_screen(unsigned char *fb_base, struct drm_mode_modeinfo *mode);
static int draw_margin_line(unsigned char *fb_base, struct drm_mode_modeinfo *mode);
static int bouncy_ball_line(unsigned char *fb_base, struct drm_mode_modeinfo *mode);

int main(int argc, char *argv[])
{
    int ret = -1, i = 0, j = 0;
    struct drm_mode_modeinfo *mode;

    if (argc > 1) drm_file = argv[1];

    if (argc > 2) mode_index = atoi(argv[2]);

    drm_fd = open(drm_file, O_RDWR | O_CLOEXEC);
    if (drm_fd < 0) {
        printf("%s open failed(%d:%s)\n", drm_file, errno, strerror(errno));
        return -errno;
    }

    ret = ioctl(drm_fd, DRM_IOCTL_SET_MASTER, NULL);
    if (ret != 0) {
        printf("%s ioctl DRM_IOCTL_SET_MASTER failed(%d:%s)\n", drm_file, errno, strerror(errno));
        goto out;
    }

    memset(&res, 0, sizeof(res));
    ret = ioctl(drm_fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
    if (ret != 0) {
        printf("%s ioctl DRM_IOCTL_MODE_GETRESOURCES size failed(%d:%s)\n", drm_file, errno, strerror(errno));
        goto out;
    }
    res.fb_id_ptr = (__u64)malloc(res.count_fbs*sizeof(int));
    memset((char *)res.fb_id_ptr, 0, res.count_fbs*sizeof(int));
    res.crtc_id_ptr = (__u64)malloc(res.count_crtcs*sizeof(int));
    memset((char *)res.crtc_id_ptr, 0, res.count_crtcs*sizeof(int));
    res.encoder_id_ptr = (__u64)malloc(res.count_encoders*sizeof(int));
    memset((char *)res.encoder_id_ptr, 0, res.count_encoders*sizeof(int));
    res.connector_id_ptr = (__u64)malloc(res.count_connectors*sizeof(int));
    memset((char *)res.connector_id_ptr, 0, res.count_connectors*sizeof(int));
    ret = ioctl(drm_fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
    if (ret != 0) {
        printf("%s ioctl DRM_IOCTL_MODE_GETRESOURCES info failed(%d:%s)\n", drm_file, errno, strerror(errno));
        goto out;
    }
    printf("\ndrm mode:\n");
    printf("\tcount_fbs\t\t%d\n", res.count_fbs);
    printf("\tfbs\t\t\t%d", res.fb_id_ptr==0?0:((int *)res.fb_id_ptr)[0]);
    for (i=1; i<res.count_fbs; i++) printf(" %d", ((int *)res.fb_id_ptr)[i]);
    printf("\n");
    printf("\tcount_crtcs\t\t%d\n", res.count_crtcs);
    printf("\tcrtcs\t\t\t%d", res.crtc_id_ptr==0?0:((int *)res.crtc_id_ptr)[0]);
    for (i=1; i<res.count_crtcs; i++) printf(" %d", ((int *)res.crtc_id_ptr)[i]);
    printf("\n");
    printf("\tcount_encoders\t\t%d\n", res.count_encoders);
    printf("\tencoders\t\t%d", res.encoder_id_ptr==0?0:((int *)res.encoder_id_ptr)[0]);
    for (i=1; i<res.count_encoders; i++) printf(" %d", ((int *)res.encoder_id_ptr)[i]);
    printf("\n");
    printf("\tcount_connectors\t%d\n", res.count_connectors);
    printf("\tconnectors\t\t%d", res.connector_id_ptr==0?0:((int *)res.connector_id_ptr)[0]);
    for (i=1; i<res.count_connectors; i++) printf(" %d", ((int *)res.connector_id_ptr)[i]);
    printf("\n");
    printf("\twidth\t\t\t%d-%d\n", res.min_width, res.max_width);
    printf("\theight\t\t\t%d-%d\n\n", res.min_height, res.max_height);

    conn = malloc(res.count_connectors*sizeof(struct drm_mode_get_connector));
    memset(conn, 0, res.count_connectors*sizeof(struct drm_mode_get_connector));
    connector_res = malloc(sizeof(connector_res_t) * CONNECTOR_MAX);
    memset(connector_res, 0, sizeof(connector_res_t) * CONNECTOR_MAX);
    for (i=0; i<res.count_connectors; i++) {
        conn[i].connector_id = ((int *)res.connector_id_ptr)[i];
        ret = ioctl(drm_fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn[i]);
        if (ret != 0) {
            printf("%s ioctl DRM_IOCTL_MODE_GETCONNECTOR on connector-%d failed(%d:%s)\n", drm_file, connector_res[i].conn->connector_id, errno, strerror(errno));
            goto out;
        }
        conn[i].encoders_ptr = (__u64)malloc(conn[i].count_encoders*sizeof(__u32));
        conn[i].modes_ptr = (__u64)malloc(conn[i].count_modes*sizeof(struct drm_mode_modeinfo));
        conn[i].props_ptr = (__u64)malloc(conn[i].count_props*sizeof(__u32));
        conn[i].prop_values_ptr = (__u64)malloc(conn[i].count_props*sizeof(__u64));
        ret = ioctl(drm_fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn[i]);
        if (ret != 0) {
            printf("%s ioctl DRM_IOCTL_MODE_GETCONNECTOR on connector-%d failed(%d:%s)\n", drm_file, connector_res[i].conn->connector_id, errno, strerror(errno));
            goto out;
        }

        if (conn[i].connection == 1 && connectors_valid < CONNECTOR_MAX) {
            connector_res[connectors_valid].conn = &conn[i];

            if (conn[i].encoder_id == 0) conn[i].encoder_id = ((int *)res.encoder_id_ptr)[i];
            connector_res[connectors_valid].enc.encoder_id = conn[i].encoder_id;
            ret = ioctl(drm_fd, DRM_IOCTL_MODE_GETENCODER, &connector_res[connectors_valid].enc);
            if (ret != 0) {
                printf("%s ioctl DRM_IOCTL_MODE_GETENCODER on connector-%d failed(%d:%s)\n", drm_file, connector_res[i].conn->connector_id, errno, strerror(errno));
                goto out;
            }

            if (connector_res[connectors_valid].enc.crtc_id == 0) connector_res[connectors_valid].enc.crtc_id = ((int *)res.crtc_id_ptr)[i];
            connector_res[connectors_valid].crtc.crtc_id = connector_res[connectors_valid].enc.crtc_id;
            ret = ioctl(drm_fd, DRM_IOCTL_MODE_GETCRTC, &connector_res[connectors_valid].crtc);
            if (ret != 0) {
                printf("%s ioctl DRM_IOCTL_MODE_GETCRTC on connector-%d failed(%d:%s)\n", drm_file, connector_res[i].conn->connector_id, errno, strerror(errno));
                goto out;
            }

            printf("connector-%d: encoder-%d, crtc-%d, mode:\n",
                    conn[i].connector_id, connector_res[connectors_valid].enc.encoder_id, connector_res[connectors_valid].enc.crtc_id);

            for (j=0; j<conn[i].count_modes; j++) {
                mode = &((struct drm_mode_modeinfo *)conn[i].modes_ptr)[j];
                printf("%d%c\t%4d x %-4d\t:clock-%-6d, sync_start-%-4d(%-4d), sync_end-%-4d(%-4d), total-%-4d(%-4d), hskew(vscan)-%-4d(%-4d)\n", j, j==mode_index?'*':'.',
                        mode->hdisplay, mode->vdisplay, mode->clock, mode->hsync_start, mode->vsync_start,
                        mode->hsync_end, mode->vsync_end, mode->htotal, mode->vtotal, mode->hskew, mode->vscan);
            }
            printf("\n");

            connectors_valid++;
        }
    }

    for (i=0; i<connectors_valid; i++) {
        mode = &((struct drm_mode_modeinfo *)connector_res[i].conn->modes_ptr)[mode_index];
        connector_res[i].create_dumb.width = mode->hdisplay;
        connector_res[i].create_dumb.height = mode->vdisplay;
        connector_res[i].create_dumb.bpp = 32;
        ret = ioctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &connector_res[i].create_dumb);
        if (ret != 0) {
            printf("%s ioctl DRM_IOCTL_MODE_CREATE_DUMB on connector-%d failed(%d:%s)\n", drm_file, connector_res[i].conn->connector_id, errno, strerror(errno));
            goto out;
        }

		connector_res[i].cmd_dumb.width = connector_res[i].create_dumb.width;
		connector_res[i].cmd_dumb.height = connector_res[i].create_dumb.height;
		connector_res[i].cmd_dumb.bpp = connector_res[i].create_dumb.bpp;
		connector_res[i].cmd_dumb.pitch = connector_res[i].create_dumb.pitch;
		connector_res[i].cmd_dumb.depth = 24;
		connector_res[i].cmd_dumb.handle = connector_res[i].create_dumb.handle;
		ret = ioctl(drm_fd, DRM_IOCTL_MODE_ADDFB, &connector_res[i].cmd_dumb);
        if (ret != 0) {
            printf("%s ioctl DRM_IOCTL_MODE_ADDFB on connector-%d failed(%d:%s)\n", drm_file, connector_res[i].conn->connector_id, errno, strerror(errno));
            goto out;
        }
        connector_res[i].destroy_dumb.handle = connector_res[i].create_dumb.handle;

        connector_res[i].map_dumb.handle = connector_res[i].create_dumb.handle;
        ret = ioctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &connector_res[i].map_dumb);
        if (ret != 0) {
            printf("%s ioctl DRM_IOCTL_MODE_MAP_DUMB on connector-%d failed(%d:%s)\n", drm_file, connector_res[i].conn->connector_id, errno, strerror(errno));
            goto out;
        }

        connector_res[i].fb_base = mmap(0, connector_res[i].create_dumb.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, connector_res[i].map_dumb.offset);
        if (connector_res[i].fb_base == NULL) {
            printf("%s mmap on connector-%d failed(%d:%s)\n", drm_file, connector_res[i].conn->connector_id, errno, strerror(errno));
            goto out;
        }

        connector_res[i].crtc.fb_id = connector_res[i].cmd_dumb.fb_id;
        connector_res[i].crtc.set_connectors_ptr = (__u64)&connector_res[i].conn->connector_id;
        connector_res[i].crtc.count_connectors = 1;
        connector_res[i].crtc.mode = *mode;
        connector_res[i].crtc.mode_valid = 1;

        printf("connector-%d add framebuff(%dx%dx%d), fb_id=0x%x, offset=0x%llx, fb_base=%p(%lld)\n\n",
                connector_res[i].conn->connector_id, connector_res[i].create_dumb.width, connector_res[i].create_dumb.height, connector_res[i].create_dumb.bpp,
                connector_res[i].cmd_dumb.fb_id, connector_res[i].map_dumb.offset, connector_res[i].fb_base, connector_res[i].create_dumb.size);

    }

    while (1) {
        for (i=0; i<connectors_valid; i++) {
            clear_screen(connector_res[i].fb_base, mode);

            draw_margin_line(connector_res[i].fb_base, mode);

            bouncy_ball_line(connector_res[i].fb_base, mode);

            ret = ioctl(drm_fd, DRM_IOCTL_MODE_SETCRTC, &connector_res[i].crtc);
            if (ret != 0) {
                printf("%s ioctl DRM_IOCTL_MODE_SETCRTC on connector-%d failed(%d:%s)\n", drm_file, connector_res[i].conn->connector_id, errno, strerror(errno));
                goto out;
            }
        }
        usleep(10*1000);
    }

out:
    ioctl(drm_fd, DRM_IOCTL_DROP_MASTER, 0);

    for (i=0; i<connectors_valid; i++) {
        if (connector_res[i].cmd_dumb.fb_id > 0) {
            ioctl(drm_fd, DRM_IOCTL_MODE_RMFB, connector_res[i].cmd_dumb.fb_id);
            connector_res[i].cmd_dumb.fb_id = 0;
        }

        if (connector_res[i].destroy_dumb.handle > 0) {
            ioctl(drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &connector_res[i].destroy_dumb);
            connector_res[i].destroy_dumb.handle = 0;
        }
    }
    if (connector_res == NULL) {
        free(connector_res);
        connector_res = NULL;
    }

    for (i=0; i<res.count_connectors; i++) {
        if (conn[i].encoders_ptr != 0) {
            free((__u32 *)conn[i].encoders_ptr);
            conn[i].encoders_ptr = 0;
        }
        if (conn[i].modes_ptr != 0) {
            free((struct drm_mode_modeinfo *)conn[i].modes_ptr);
            conn[i].modes_ptr = 0;
        }
        if (conn[i].props_ptr != 0) {
            free((__u32 *)conn[i].props_ptr);
            conn[i].props_ptr = 0;
        }
        if (conn[i].prop_values_ptr != 0) {
            free((__u64 *)conn[i].prop_values_ptr);
            conn[i].prop_values_ptr = 0;
        }
    }

    if (conn != NULL) {
        free(conn);
        conn = NULL;
    }

    if (res.fb_id_ptr != 0) {
        free((int *)res.fb_id_ptr);
        res.fb_id_ptr = 0;
    }
    if (res.crtc_id_ptr != 0) {
        free((int *)res.crtc_id_ptr);
        res.crtc_id_ptr = 0;
    }
    if (res.encoder_id_ptr != 0) {
        free((int *)res.encoder_id_ptr);
        res.encoder_id_ptr = 0;
    }
    if (res.connector_id_ptr != 0) {
        free((int *)res.connector_id_ptr);
        res.connector_id_ptr = 0;
    }

    if (drm_fd >= 0) {
        close(drm_fd);
        drm_fd = -1;
    }

    return ret;
}

#define RED_FULL    0xFF0000
#define GREEE_FULL  0x00FF00
#define BLUE_FULL   0x0000FF

typedef struct {
    int x;
    int y;
} coo_d_t;

#define FB_MEM_32(x, y)   ((__u32 *)fb_base + y*mode->hdisplay + x)

static int clear_screen(unsigned char *fb_base, struct drm_mode_modeinfo *mode)
{
    memset(fb_base, 0x00, mode->hdisplay * mode->vdisplay * 4);
}

static int draw_margin_line(unsigned char *fb_base, struct drm_mode_modeinfo *mode)
{
    int x, y;

    for (x=0; x<mode->hdisplay; x++) {/* y=0 */
        y = 0;
        *(FB_MEM_32(x,y)) = GREEE_FULL;
    }

    for (y=0; y<mode->vdisplay; y++) {/* x=width */
        x = mode->hdisplay-1;
        *(FB_MEM_32(x,y)) = GREEE_FULL;
    }

    for (x=0; x<mode->hdisplay; x++) {/* y=height */
        y = mode->vdisplay-1;
        *(FB_MEM_32(x,y)) = GREEE_FULL;
    }

    for (y=0; y<mode->vdisplay; y++) {/* x=0 */
        x = 0;
        *(FB_MEM_32(x,y)) = GREEE_FULL;
    }

    return 0;
}

static int draw_line(unsigned char *fb_base, struct drm_mode_modeinfo *mode, coo_d_t p1, coo_d_t p2, int color)
{
    int x, y, t;
    float a, b;

    if (p1.x == p2.x) {
        if (p1.y > p2.y) {
            t = p1.y;
            p1.y = p2.y;
            p2.y = t;
        }
        for (y=p1.y; y<p2.y; y++) {
            x = p1.x;
            if (x>=0 && x<mode->hdisplay && y>=0 && y<mode->vdisplay)
                *(FB_MEM_32(x,y)) = color;
        }
    }

    /* y = ax + b */
    a = (float)(p2.y-p1.y)/(p2.x-p1.x);
    b = (float)((p1.y+p2.y) - a*(p1.x+p2.x))/2;

    if (p1.x > p2.x) {
        t = p1.x;
        p1.x = p2.x;
        p2.x = t;
    }
    for (x=p1.x; x<=p2.x; x++) {
        y = a*x + b;
        if (x>=0 && x<mode->hdisplay && y>=0 && y<mode->vdisplay)
            *(FB_MEM_32(x,y)) = color;
    }

    if (p1.y > p2.y) {
        t = p1.y;
        p1.y = p2.y;
        p2.y = t;
    }
    for (y=p1.y; y<p2.y; y++) {
        x = (y-b)/a;
        if (x>=0 && x<mode->hdisplay && y>=0 && y<mode->vdisplay)
            *(FB_MEM_32(x,y)) = color;
    }

    return 0;
}

static int draw_circle(unsigned char *fb_base, struct drm_mode_modeinfo *mode, coo_d_t p, int r, __u32 color)
{
    /* circle: center(a,b), r(r), (x-a)^2 + (y-b)^2 = r^2 */
    int x, y;

    for (x = p.x-r; x <= p.x+r; x++) {
        y = (sqrtf(r*r-((x-p.x)*(x-p.x)))+0.5) + p.y;
        if (x>=0 && x<mode->hdisplay && y>=0 && y<mode->vdisplay)
            *(FB_MEM_32(x,y)) = color;

        y = p.y - (sqrtf(r*r-((x-p.x)*(x-p.x)))+0.5);
        if (x>=0 && x<mode->hdisplay && y>=0 && y<mode->vdisplay)
            *(FB_MEM_32(x,y)) = color;
    }

    for (y = p.y-r; y <= p.y+r; y++) {
        x = (sqrtf(r*r-((y-p.y)*(y-p.y)))+0.5) + p.x;
        if (x>=0 && x<mode->hdisplay && y>=0 && y<mode->vdisplay)
            *(FB_MEM_32(x,y)) = color;

        x = p.x - (sqrtf(r*r-((y-p.y)*(y-p.y)))+0.5);
        if (x>=0 && x<mode->hdisplay && y>=0 && y<mode->vdisplay)
            *(FB_MEM_32(x,y)) = color;
    }

    return 0;
}

static int circle_line_cross(unsigned char *fb_base, struct drm_mode_modeinfo *mode, coo_d_t p1, coo_d_t p2, coo_d_t o, int r)
{
    int x, y, t, c_x, c_y;
    float a, b;

    if (p1.x == p2.x) {
        if (p1.y > p2.y) {
            t = p1.y;
            p1.y = p2.y;
            p2.y = t;
        }
        for (y=p1.y; y<p2.y; y++) {
            x = p1.x;
            if (x>=0 && x<mode->hdisplay && y>=0 && y<mode->vdisplay) {
                c_y = (sqrtf(r*r - ((x-o.x)*(x-o.x)))+0.5) + o.y;
                if (y == c_y) return 1;
                c_y = o.y - (sqrtf(r*r - ((x-o.x)*(x-o.x)))+0.5);
                if (y == c_y) return 1;
            }
        }
    }

    /* y = ax + b */
    a = (float)(p2.y-p1.y)/(p2.x-p1.x);
    b = (float)((p1.y+p2.y) - a*(p1.x+p2.x))/2;

    if (p1.x > p2.x) {
        t = p1.x;
        p1.x = p2.x;
        p2.x = t;
    }
    for (x=p1.x; x<=p2.x; x++) {
        y = a*x + b;
        if (x>=0 && x<mode->hdisplay && y>=0 && y<mode->vdisplay) {
            c_y = (sqrtf(r*r - ((x-o.x)*(x-o.x)))+0.5) + o.y;
            if ((y-c_y)*(y-c_y) <= 4 ) return 1;
            c_y = o.y - (sqrtf(r*r - ((x-o.x)*(x-o.x)))+0.5);
            if ((y-c_y)*(y-c_y) <= 4 ) return 1;
        }
    }

    if (p1.y > p2.y) {
        t = p1.y;
        p1.y = p2.y;
        p2.y = t;
    }
    for (y=p1.y; y<p2.y; y++) {
        x = (y-b)/a;
        if (x>=0 && x<mode->hdisplay && y>=0 && y<mode->vdisplay) {
            c_x = (sqrtf(r*r - ((y-o.y)*(y-o.y)))+0.5) + o.x;
            if (x == c_x) return 1;
            if ((x-c_x)*(x-c_x) <= 4) return 1;
            c_x = o.x - (sqrtf(r*r - ((y-o.y)*(y-o.y)))+0.5);
            if ((x-c_x)*(x-c_x) <= 4) return 1;
        }
    }

    return 0;
}

static int circle_cross(coo_d_t o1, int r1, coo_d_t o2, int r2)
{
    int pitch = 0;

    pitch = sqrtf((o2.x-o1.x)*(o2.x-o1.x) + (o2.y-o1.y)*(o2.y-o1.y))+0.5;

    return pitch-r1-r2 <= 0;
}

static int bouncy_ball_line(unsigned char *fb_base, struct drm_mode_modeinfo *mode)
{
    static int r = 200, r_2 = 150;
    static coo_d_t o = { 200, 200 }, o_2 = { 600, 600 };
    static coo_d_t o_d = { 1, 2 }, o_d_2 = { 2, 1 };
    static coo_d_t p1 = { 600, 100 }, p2 = { 600, 400 };
    static __u32 color_c = RED_FULL, color_c_2 = RED_FULL, color_l = BLUE_FULL;
    int sign = 1;

    draw_line(fb_base, mode, p1, p2 , color_l);

    draw_circle(fb_base, mode, o, r, color_c);
    draw_circle(fb_base, mode, o_2, r_2, color_c_2);

    if (circle_cross(o, r, o_2, r_2)) {
        if (o_2.x - o.x > 0) {
            if (o_d.x > 0)
                o_d.x *= -1;
            if (o_d_2.x < 0)
                o_d_2.x *= -1;
        }

        if (o.x - o_2.x > 0) {
            if (o_d.x < 0)
                o_d.x *= -1;
            if (o_d_2.x > 0)
                o_d_2.x *= -1;
        }

        if (o_2.y - o.y > 0) {
            if (o_d.y > 0)
                o_d.y *= -1;
            if (o_d_2.y < 0)
                o_d_2.y *= -1;
        }

        if (o.y - o_2.y > 0) {
            if (o_d.y < 0)
                o_d.y *= -1;
            if (o_d_2.y > 0)
                o_d_2.y *= -1;
        }

        color_c = random();
        color_c_2 = random();

        if (random()%2) sign = 1;
        else sign = -1;
        o_d.x += (random()%2)*sign;
        o_d.y += (random()%2)*sign;
        o_d_2.x += (random()%2)*sign;
        o_d_2.y += (random()%2)*sign;
    }

    if ((o.x-r<0 && o_d.x<0) || (o.x+r>=mode->hdisplay && o_d.x>0)) {
        o_d.x *= -1;
        color_c = random();
    }
    if ((o.y-r<0 && o_d.y<0) || (o.y+r>=mode->vdisplay&& o_d.y>0)) {
        o_d.y *= -1;
        color_c = random();
    }

    if ((o_2.x-r_2<0 && o_d_2.x<0) || (o_2.x+r_2>=mode->hdisplay && o_d_2.x>0)) {
        o_d_2.x *= -1;
        color_c_2 = random();
    }
    if ((o_2.y-r_2<0 && o_d_2.y<0) || (o_2.y+r_2>=mode->vdisplay&&o_d_2.y>0)) {
        o_d_2.y *= -1;
        color_c_2 = random();
    }

    while (circle_line_cross(fb_base, mode, p1, p2, o, r) || circle_line_cross(fb_base, mode, p1, p2, o_2, r_2)) {
        p1.x = random()%mode->hdisplay;
        p1.y = random()%mode->vdisplay;
        p2.x = random()%mode->hdisplay;
        p2.y = random()%mode->vdisplay;
        color_l = random();
    }

    o.x += o_d.x;
    o.y += o_d.y;

    o_2.x += o_d_2.x;
    o_2.y += o_d_2.y;

    return 0;
}
